<template>
  <div class="max-w-3xl mx-auto p-6">
    <h1 class="text-2xl font-semibold">图片压缩（Image Compress）</h1>

    <div class="mb-4 p-4 bg-gray-50 border border-gray-200 rounded">
      <h2 class="text-lg font-medium mb-2">使用说明</h2>
      <ol class="list-decimal list-inside text-sm text-gray-700 space-y-1 mb-2">
        <li>上传图片：点击区域或拖拽上传，支持常见图片格式（JPEG / PNG / WEBP / GIF）。</li>
        <li>选择输出格式：<strong>JPEG</strong>（有损，支持质量调节）、<strong>PNG</strong>（无损，质量参数对体积影响有限）、<strong>WEBP</strong>（现代高压缩率）。</li>
        <li>调整质量：使用滑块控制质量（10%~100%），较低质量可显著减小体积，但可能出现可见压缩痕迹；对 PNG 通常不明显。</li>
        <li>设置最大宽度：填写 px 值可按比例缩放宽度，留空或填 0 表示不改变分辨率。</li>
        <li>点击“开始压缩”进行客户端处理，完成后在右侧查看预览并下载结果。</li>
      </ol>
      <h3 class="text-sm font-medium mb-1">注意事项</h3>
      <ul class="list-disc list-inside text-sm text-gray-700 space-y-1">
        <li>所有压缩操作在浏览器端完成，不会上传到服务器，保证隐私与速度。</li>
        <li>将带透明通道（Alpha）的图片转换为 JPEG 会把透明区域填充为白色。</li>
        <li>对非常大的图片（例如超过 4000px）可能较慢或导致内存占用较高，建议先设置最大宽度。</li>
        <li>PNG 的“质量”参数对无损 PNG 影响有限，如需更小体积可尝试转换为 WEBP 或 JPEG（注意透明问题）。</li>
        <li>若原图为动画 GIF，当前工具仅处理第一帧（静态），动画不会保留。</li>
        <li>如果压缩失败，请检查浏览器控制台中的错误信息或尝试更改格式/质量后重试。</li>
      </ul>
    </div>

    <div class="mt-6 grid grid-cols-1 md:grid-cols-2 gap-6">
      <div>
        <label class="block mb-2 text-sm font-medium text-gray-700">选择图片</label>
        <div
          class="border-2 border-dashed border-gray-200 rounded-lg p-6 text-center hover:border-blue-300 transition-colors"
          @click="triggerFileInput"
        >
          <input ref="fileInput" type="file" accept="image/*" class="hidden" @change="onFileChange" />
          <div v-if="!originalDataUrl" class="text-gray-500">
            点击或拖拽上传图片（支持 JPEG / PNG / WEBP 等）
          </div>
          <div v-else class="flex flex-col items-center">
            <img :src="originalDataUrl" alt="原始图片" class="max-h-48 object-contain mb-3 rounded" />
            <div class="text-sm text-gray-600">原始: {{ formatFileSize(originalSize) }}</div>
          </div>
        </div>

        <div class="mt-4 space-y-3">
          <div>
            <label class="block text-sm text-gray-700 mb-1">输出格式</label>
            <select v-model="options.format" class="input-field w-full">
              <option value="image/jpeg">JPEG (有损，支持质量调整)</option>
              <option value="image/png">PNG (无损，质量参数可能无效)</option>
              <option value="image/webp">WEBP (高压缩率，现代浏览器支持)</option>
            </select>
          </div>

          <div>
            <label class="block text-sm text-gray-700 mb-1">质量：<span class="font-medium">{{ Math.round(options.quality * 100) }}%</span></label>
            <input type="range" min="0.1" max="1" step="0.05" v-model.number="options.quality" class="w-full" />
            <p class="text-xs text-gray-500 mt-1">较低质量会显著减小文件体积，但可能降低视觉效果。对 PNG 来说影响有限。</p>
          </div>

          <div>
            <label class="block text-sm text-gray-700 mb-1">最大宽度 (px)</label>
            <input type="number" v-model.number="options.maxWidth" min="0" placeholder="自动" class="input-field w-full" />
            <p class="text-xs text-gray-500 mt-1">留空或填 0 表示不限制宽度，只按原始尺寸。</p>
          </div>

          <div class="flex space-x-2 mt-3">
            <button @click="compress" :disabled="!originalImage || processing" class="primary-button">
              {{ processing ? '压缩中...' : '开始压缩' }}
            </button>
            <button @click="reset" type="button" class="ml-2 inline-block px-4 py-2 border rounded text-sm" :disabled="processing">重置</button>
          </div>
        </div>
      </div>

      <div>
        <label class="block mb-2 text-sm font-medium text-gray-700">预览 & 下载</label>
        <div class="border rounded-lg p-4">
          <div v-if="!originalDataUrl" class="text-gray-500">尚未上传图片</div>

          <div v-else class="space-y-3">
            <div class="grid grid-cols-1 gap-3">
              <div>
                <div class="text-sm font-medium">原图预览</div>
                <img :src="originalDataUrl" alt="原图" class="max-h-40 object-contain rounded mt-2" />
              </div>

              <div v-if="outputUrl">
                <div class="text-sm font-medium">压缩后预览</div>
                <img :src="outputUrl" alt="压缩后" class="max-h-40 object-contain rounded mt-2" />
              </div>

              <div class="flex items-center justify-between">
                <div>
                  <div class="text-xs text-gray-600">原始大小：{{ formatFileSize(originalSize) }}</div>
                  <div v-if="outputBlob" class="text-xs text-gray-600">压缩后：{{ formatFileSize(outputSize) }}</div>
                </div>
                <div>
                  <button v-if="outputBlob" @click="downloadResult" class="primary-button">下载</button>
                </div>
              </div>

              <div v-if="warnText" class="text-xs text-yellow-700">{{ warnText }}</div>
            </div>
          </div>
        </div>

        <nuxt-link to="/image-tools" class="mt-4 inline-block text-blue-500">返回图片工具</nuxt-link>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref } from 'vue'
import { useTools } from '~/composables/useTools'
useHead({ title: '图片压缩 - 图片工具' })

const { readImageFile, formatFileSize } = useTools()

const fileInput = ref(null)
const originalDataUrl = ref(null)
const originalImage = ref(null)
const originalSize = ref(0)

const outputBlob = ref(null)
const outputUrl = ref(null)
const outputSize = ref(0)

const processing = ref(false)
const warnText = ref('')

const options = ref({
  format: 'image/jpeg',
  quality: 0.8,
  maxWidth: 0
})

const triggerFileInput = () => {
  fileInput.value && fileInput.value.click()
}

const onFileChange = async (e) => {
  const f = e.target.files && e.target.files[0]
  if (!f) return
  if (!f.type.startsWith('image/')) {
    warnText.value = '请选择图片文件'
    return
  }
  warnText.value = ''
  originalSize.value = f.size
  const res = await readImageFile(f)
  originalDataUrl.value = res.dataUrl
  originalImage.value = res.image
  // 清理之前的结果
  clearOutput()
}

const clearOutput = () => {
  if (outputUrl.value) URL.revokeObjectURL(outputUrl.value)
  outputBlob.value = null
  outputUrl.value = null
  outputSize.value = 0
}

const compress = async () => {
  if (!originalImage.value) return
  processing.value = true
  warnText.value = ''

  try {
    const img = originalImage.value
    const mime = options.value.format
    const quality = options.value.quality

    // 计算目标尺寸
    let targetW = img.width
    let targetH = img.height
    const maxW = Number(options.value.maxWidth) || 0
    if (maxW > 0 && targetW > maxW) {
      const ratio = maxW / targetW
      targetW = Math.round(targetW * ratio)
      targetH = Math.round(targetH * ratio)
    }

    const canvas = document.createElement('canvas')
    canvas.width = targetW
    canvas.height = targetH
    const ctx = canvas.getContext('2d')
    // 对于有透明通道的 PNG -> JPEG 会丢失透明性，给出提示
    if (mime === 'image/jpeg' && hasTransparency(img)) {
      warnText.value = '注意：当前图片包含透明通道，转换为 JPEG 时透明部分会变为白色。'
    }
    ctx.drawImage(img, 0, 0, targetW, targetH)

    await new Promise((resolve) => {
      canvas.toBlob((blob) => {
        if (!blob) {
          warnText.value = '压缩失败：无法生成 Blob'
          processing.value = false
          resolve()
          return
        }
        clearOutput()
        outputBlob.value = blob
        outputUrl.value = URL.createObjectURL(blob)
        outputSize.value = blob.size
        resolve()
      }, mime, quality)
    })
  } catch (err) {
    console.error(err)
    warnText.value = '压缩时发生错误，请检查控制台。'
  } finally {
    processing.value = false
  }
}

const hasTransparency = (image) => {
  try {
    const c = document.createElement('canvas')
    c.width = image.width
    c.height = image.height
    const ctx = c.getContext('2d')
    ctx.drawImage(image, 0, 0)
    const data = ctx.getImageData(0, 0, Math.min(10, c.width), Math.min(10, c.height)).data
    for (let i = 3; i < data.length; i += 4) {
      if (data[i] < 255) return true
    }
    return false
  } catch (e) {
    return false
  }
}

const downloadResult = () => {
  if (!outputBlob.value) return
  const ext = mimeToExt(options.value.format)
  const filename = `compressed-${Date.now()}.${ext}`
  const url = URL.createObjectURL(outputBlob.value)
  const a = document.createElement('a')
  a.href = url
  a.download = filename
  a.click()
  URL.revokeObjectURL(url)
}

const mimeToExt = (mime) => {
  if (mime === 'image/jpeg') return 'jpg'
  if (mime === 'image/png') return 'png'
  if (mime === 'image/webp') return 'webp'
  return 'img'
}

const reset = () => {
  originalDataUrl.value = null
  originalImage.value = null
  originalSize.value = 0
  clearOutput()
  warnText.value = ''
  if (fileInput.value) fileInput.value.value = null
}

</script>
